if(true){
    var foo = 'zce'
}
console.log(foo)// zec 这种情况当代码复杂时是不利的
//=======================================
if(true){
    let foo = 'zce'
}
console.log(foo) //foo is not defined
// let let声明后其作用域在大括号内，外部无法访问
//========================================================
for(var i = 0; i< 3; i++){
    for(var i = 0; i< 3; i++){
        console.log(i)
    }
    console.log('内层结束 i=' +i)// 内层结束 i = 3
}

// 0 1 2
//外层声明了i过后，内层再次声明这个变量，都是使用var声明，并不是一个块级作用域内的成员，而是全局成员，内层所声明的i会覆盖掉外层声明的i，等内层循环完之后，内层的i为3，对于外层仍然是3，所以不会继续循环了

//===============================================================
for(let i = 0; i< 3; i++){
    for(let i = 0; i< 3; i++){
        console.log(i)
    }
    console.log('内层结束 i=' +i)
}
// i为内部的块级作用域的局部成员,内层循环的let 把i关进了一个盒子当中，并不影响外部成员，即便把外部的let改为var也是可以的
//=====================================================
var elements = [{},{},{}]
for(var i = 0;i<elements.length;i++){
    elements[i].onclick = function(){
        console.log(i)
    }
}
elements[0].onclick()// 这里的i无论是几，结果都是3
//打印的i始终是全局作用域的i，循环完成之后i被累加到了3，最后结果都是3
//====================================
//建立闭包机制避免上述问题
var elements = [{},{},{}]
for(var i = 0;i<elements.length;i++){
    elements[i].onclick = (function(i){
        return function(){
            console.log(i)
        }
    })(i)
}//闭包利用函数作用域去摆脱全局作用域产生的影响
elements[0].onclick()
//闭包机制较为复杂， 将var改为let就解决了
//============================
for(let i=0;i<3;i++){
    let i = 'foo'
    console.log(i)//foo foo foo
    //两个i不在同一个作用域当中
}
//拆解如下：
let i = 0;

if(i<3){
    let i = 'foo'// i为if语句内部的独立的局部作用域，外部循环的计数器是外部循环产生的作用域，所以是互不影响的
    console.log(i)
}

i++

if(i<3){
    let i = 'foo'
    console.log(i)
}

i++

if(i<3){
    let i = 'foo'
    console.log(i)
}

i++

// ============================
console.log(foo)//undefined 说明打印的时候，此时的foo已经声明了，只是还没有赋值而已，这种现象叫做变量声明的提升
var foo = 'zec'
//================
console.log(foo)//Cannot access 'foo' before initialization(引用异常的错误)
let foo = 'zec'